﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using CounterStrikeSourceAimbot;

namespace CounterStrikeSourceAimbot_WpfControls
{
	/// <summary>
	/// Interaction logic for MapControl.xaml
	/// </summary>
	public partial class MapControl : UserControl
	{
	    public MapControl()
	    {
	        this.PlayerXConverter = new PlayerCoordConverter()
	        {
	            Control = this,
	            Type = PlayerCoordConverter.CoordType.X
	        };

	        this.PlayerYConverter = new PlayerCoordConverter()
	        {
	            Control = this,
	            Type = PlayerCoordConverter.CoordType.Y
	        };


	        this.InitializeComponent();
	    }

	    #region WorldData Property and Property Change Routed event

	    public static readonly DependencyProperty WorldDataProperty
	        = DependencyProperty.Register(
	            "WorldData", typeof (WorldData), typeof (MapControl),
	            new PropertyMetadata(null, OnWorldDataChanged, WorldDataCoerceValue));

	    public WorldData WorldData
	    {
	        get { return (WorldData) GetValue(WorldDataProperty); }
	        set { SetValue(WorldDataProperty, value); }
	    }

	    public static readonly RoutedEvent WorldDataChangedEvent
	        = EventManager.RegisterRoutedEvent(
	            "WorldDataChanged",
	            RoutingStrategy.Direct,
	            typeof (RoutedPropertyChangedEventHandler<WorldData>),
	            typeof (MapControl));

	    private static object WorldDataCoerceValue(DependencyObject d, object value)
	    {
	        var val = (WorldData) value;
	        var obj = (MapControl) d;


	        return value;
	    }

	    public event RoutedPropertyChangedEventHandler<WorldData> WorldDataChanged
	    {
	        add { AddHandler(WorldDataChangedEvent, value); }
	        remove { RemoveHandler(WorldDataChangedEvent, value); }
	    }

	    private static void OnWorldDataChanged(
	        DependencyObject d,
	        DependencyPropertyChangedEventArgs e)
	    {
	        var obj = d as MapControl;
	        var args = new RoutedPropertyChangedEventArgs<WorldData>(
	            (WorldData) e.OldValue,
	            (WorldData) e.NewValue);
	        args.RoutedEvent = MapControl.WorldDataChangedEvent;
	        obj.RaiseEvent(args);
	        
	    }


	    #endregion

	    #region AlfaX Property and Property Change Routed event

	    public static readonly DependencyProperty AlfaXProperty
	        = DependencyProperty.Register(
	            "AlfaX", typeof (double), typeof (MapControl),
	            new PropertyMetadata(0.0, OnAlfaXChanged, AlfaXCoerceValue));

	    public double AlfaX
	    {
	        get { return (double) GetValue(AlfaXProperty); }
	        set { SetValue(AlfaXProperty, value); }
	    }

	    public static readonly RoutedEvent AlfaXChangedEvent
	        = EventManager.RegisterRoutedEvent(
	            "AlfaXChanged",
	            RoutingStrategy.Direct,
	            typeof (RoutedPropertyChangedEventHandler<double>),
	            typeof (MapControl));

	    private static object AlfaXCoerceValue(DependencyObject d, object value)
	    {
	        var val = (double) value;
	        var obj = (MapControl) d;


	        return value;
	    }

	    public event RoutedPropertyChangedEventHandler<double> AlfaXChanged
	    {
	        add { AddHandler(AlfaXChangedEvent, value); }
	        remove { RemoveHandler(AlfaXChangedEvent, value); }
	    }

	    private static void OnAlfaXChanged(
	        DependencyObject d,
	        DependencyPropertyChangedEventArgs e)
	    {
	        var obj = d as MapControl;
	        var args = new RoutedPropertyChangedEventArgs<double>(
	            (double) e.OldValue,
	            (double) e.NewValue);
	        args.RoutedEvent = MapControl.AlfaXChangedEvent;
	        obj.RaiseEvent(args);
	    }


	    #endregion

	    #region AlfaY Property and Property Change Routed event

	    public static readonly DependencyProperty AlfaYProperty
	        = DependencyProperty.Register(
	            "AlfaY", typeof (double), typeof (MapControl),
	            new PropertyMetadata(0.0, OnAlfaYChanged, AlfaYCoerceValue));

	    public double AlfaY
	    {
	        get { return (double) GetValue(AlfaYProperty); }
	        set { SetValue(AlfaYProperty, value); }
	    }

	    public static readonly RoutedEvent AlfaYChangedEvent
	        = EventManager.RegisterRoutedEvent(
	            "AlfaYChanged",
	            RoutingStrategy.Direct,
	            typeof (RoutedPropertyChangedEventHandler<double>),
	            typeof (MapControl));

	    private static object AlfaYCoerceValue(DependencyObject d, object value)
	    {
	        var val = (double) value;
	        var obj = (MapControl) d;


	        return value;
	    }

	    public event RoutedPropertyChangedEventHandler<double> AlfaYChanged
	    {
	        add { AddHandler(AlfaYChangedEvent, value); }
	        remove { RemoveHandler(AlfaYChangedEvent, value); }
	    }

	    private static void OnAlfaYChanged(
	        DependencyObject d,
	        DependencyPropertyChangedEventArgs e)
	    {
	        var obj = d as MapControl;
	        var args = new RoutedPropertyChangedEventArgs<double>(
	            (double) e.OldValue,
	            (double) e.NewValue);
	        args.RoutedEvent = MapControl.AlfaYChangedEvent;
	        obj.RaiseEvent(args);
	    }


	    #endregion

	    #region BetaX Property and Property Change Routed event

	    public static readonly DependencyProperty BetaXProperty
	        = DependencyProperty.Register(
	            "BetaX", typeof (double), typeof (MapControl),
	            new PropertyMetadata(0.0, OnBetaXChanged, BetaXCoerceValue));

	    public double BetaX
	    {
	        get { return (double) GetValue(BetaXProperty); }
	        set { SetValue(BetaXProperty, value); }
	    }

	    public static readonly RoutedEvent BetaXChangedEvent
	        = EventManager.RegisterRoutedEvent(
	            "BetaXChanged",
	            RoutingStrategy.Direct,
	            typeof (RoutedPropertyChangedEventHandler<double>),
	            typeof (MapControl));

	    private static object BetaXCoerceValue(DependencyObject d, object value)
	    {
	        var val = (double) value;
	        var obj = (MapControl) d;


	        return value;
	    }

	    public event RoutedPropertyChangedEventHandler<double> BetaXChanged
	    {
	        add { AddHandler(BetaXChangedEvent, value); }
	        remove { RemoveHandler(BetaXChangedEvent, value); }
	    }

	    private static void OnBetaXChanged(
	        DependencyObject d,
	        DependencyPropertyChangedEventArgs e)
	    {
	        var obj = d as MapControl;
	        var args = new RoutedPropertyChangedEventArgs<double>(
	            (double) e.OldValue,
	            (double) e.NewValue);
	        args.RoutedEvent = MapControl.BetaXChangedEvent;
	        obj.RaiseEvent(args);
	    }


	    #endregion

	    #region BetaY Property and Property Change Routed event

	    public static readonly DependencyProperty BetaYProperty
	        = DependencyProperty.Register(
	            "BetaY", typeof (double), typeof (MapControl),
	            new PropertyMetadata(0.0, OnBetaYChanged, BetaYCoerceValue));

	    public double BetaY
	    {
	        get { return (double) GetValue(BetaYProperty); }
	        set { SetValue(BetaYProperty, value); }
	    }

	    public static readonly RoutedEvent BetaYChangedEvent
	        = EventManager.RegisterRoutedEvent(
	            "BetaYChanged",
	            RoutingStrategy.Direct,
	            typeof (RoutedPropertyChangedEventHandler<double>),
	            typeof (MapControl));

	    private static object BetaYCoerceValue(DependencyObject d, object value)
	    {
	        var val = (double) value;
	        var obj = (MapControl) d;


	        return value;
	    }

	    public event RoutedPropertyChangedEventHandler<double> BetaYChanged
	    {
	        add { AddHandler(BetaYChangedEvent, value); }
	        remove { RemoveHandler(BetaYChangedEvent, value); }
	    }

	    private static void OnBetaYChanged(
	        DependencyObject d,
	        DependencyPropertyChangedEventArgs e)
	    {
	        var obj = d as MapControl;
	        var args = new RoutedPropertyChangedEventArgs<double>(
	            (double) e.OldValue,
	            (double) e.NewValue);
	        args.RoutedEvent = MapControl.BetaYChangedEvent;
	        obj.RaiseEvent(args);
	    }


	    #endregion

	    #region PlayerXConverter Property and Property Change Routed event

	    public static readonly DependencyProperty PlayerXConverterProperty
	        = DependencyProperty.Register(
	            "PlayerXConverter", typeof (PlayerCoordConverter), typeof (MapControl),
	            new PropertyMetadata(null, OnPlayerXConverterChanged, PlayerXConverterCoerceValue));

	    public PlayerCoordConverter PlayerXConverter
	    {
	        get { return (PlayerCoordConverter) GetValue(PlayerXConverterProperty); }
	        set { SetValue(PlayerXConverterProperty, value); }
	    }

	    public static readonly RoutedEvent PlayerXConverterChangedEvent
	        = EventManager.RegisterRoutedEvent(
	            "PlayerXConverterChanged",
	            RoutingStrategy.Direct,
	            typeof (RoutedPropertyChangedEventHandler<PlayerCoordConverter>),
	            typeof (MapControl));

	    private static object PlayerXConverterCoerceValue(DependencyObject d, object value)
	    {
	        var val = (PlayerCoordConverter) value;
	        var obj = (MapControl) d;


	        return value;
	    }

	    public event RoutedPropertyChangedEventHandler<PlayerCoordConverter> PlayerXConverterChanged
	    {
	        add { AddHandler(PlayerXConverterChangedEvent, value); }
	        remove { RemoveHandler(PlayerXConverterChangedEvent, value); }
	    }

	    private static void OnPlayerXConverterChanged(
	        DependencyObject d,
	        DependencyPropertyChangedEventArgs e)
	    {
	        var obj = d as MapControl;
	        var args = new RoutedPropertyChangedEventArgs<PlayerCoordConverter>(
	            (PlayerCoordConverter) e.OldValue,
	            (PlayerCoordConverter) e.NewValue);
	        args.RoutedEvent = MapControl.PlayerXConverterChangedEvent;
	        obj.RaiseEvent(args);
	        
	    }


	    #endregion

	    #region PlayerYConverter Property and Property Change Routed event

	    public static readonly DependencyProperty PlayerYConverterProperty
	        = DependencyProperty.Register(
	            "PlayerYConverter", typeof (PlayerCoordConverter), typeof (MapControl),
	            new PropertyMetadata(null, OnPlayerYConverterChanged, PlayerYConverterCoerceValue));

	    public PlayerCoordConverter PlayerYConverter
	    {
	        get { return (PlayerCoordConverter) GetValue(PlayerYConverterProperty); }
	        set { SetValue(PlayerYConverterProperty, value); }
	    }

	    public static readonly RoutedEvent PlayerYConverterChangedEvent
	        = EventManager.RegisterRoutedEvent(
	            "PlayerYConverterChanged",
	            RoutingStrategy.Direct,
	            typeof (RoutedPropertyChangedEventHandler<PlayerCoordConverter>),
	            typeof (MapControl));

	    private static object PlayerYConverterCoerceValue(DependencyObject d, object value)
	    {
	        var val = (PlayerCoordConverter) value;
	        var obj = (MapControl) d;


	        return value;
	    }

	    public event RoutedPropertyChangedEventHandler<PlayerCoordConverter> PlayerYConverterChanged
	    {
	        add { AddHandler(PlayerYConverterChangedEvent, value); }
	        remove { RemoveHandler(PlayerYConverterChangedEvent, value); }
	    }

	    private static void OnPlayerYConverterChanged(
	        DependencyObject d,
	        DependencyPropertyChangedEventArgs e)
	    {
	        var obj = d as MapControl;
	        var args = new RoutedPropertyChangedEventArgs<PlayerCoordConverter>(
	            (PlayerCoordConverter) e.OldValue,
	            (PlayerCoordConverter) e.NewValue);
	        args.RoutedEvent = MapControl.PlayerYConverterChangedEvent;
	        obj.RaiseEvent(args);
	        
	    }


	    #endregion

	    #region Players Property and Property Change Routed event

	    public static readonly DependencyProperty PlayersProperty
	        = DependencyProperty.Register(
	            "Players", typeof (ObservableCollection<PlayerData>), typeof (MapControl),
	            new PropertyMetadata(null, OnPlayersChanged, PlayersCoerceValue));

	    public ObservableCollection<PlayerData> Players
	    {
	        get { return (ObservableCollection<PlayerData>) GetValue(PlayersProperty); }
	        set { SetValue(PlayersProperty, value); }
	    }

	    public static readonly RoutedEvent PlayersChangedEvent
	        = EventManager.RegisterRoutedEvent(
	            "PlayersChanged",
	            RoutingStrategy.Direct,
	            typeof (RoutedPropertyChangedEventHandler<ObservableCollection<PlayerData>>),
	            typeof (MapControl));

	    private static object PlayersCoerceValue(DependencyObject d, object value)
	    {
	        var val = (ObservableCollection<PlayerData>) value;
	        var obj = (MapControl) d;


	        return value;
	    }

	    public event RoutedPropertyChangedEventHandler<ObservableCollection<PlayerData>> PlayersChanged
	    {
	        add { AddHandler(PlayersChangedEvent, value); }
	        remove { RemoveHandler(PlayersChangedEvent, value); }
	    }

	    private static void OnPlayersChanged(
	        DependencyObject d,
	        DependencyPropertyChangedEventArgs e)
	    {
	        var obj = d as MapControl;
	        var args = new RoutedPropertyChangedEventArgs<ObservableCollection<PlayerData>>(
	            (ObservableCollection<PlayerData>) e.OldValue,
	            (ObservableCollection<PlayerData>) e.NewValue);
	        args.RoutedEvent = MapControl.PlayersChangedEvent;
	        obj.RaiseEvent(args);

            if (e.NewValue != null)
                (e.NewValue as ObservableCollection<PlayerData>).CollectionChanged += obj.OnCollectionChanged;

            if (e.OldValue != null)
                (e.OldValue as ObservableCollection<PlayerData>).CollectionChanged -= obj.OnCollectionChanged;

	        obj.ReloadPlayersToMap();
	    }

	    private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
	    {
	        ReloadPlayersToMap();
	    }

	    public void ReloadPlayersToMap()
	    {
            var childs = MainCanvas.Children.Cast<object>().ToList();

            foreach (var child in childs)
                if (child is PersonSymbol)
                    MainCanvas.Children.Remove(child as PersonSymbol);

            if (this.Players != null)
                foreach (var player in this.Players)
                {
                    var ps = new PersonSymbol();

                    ps.Parent = this;
                    ps.Context = player;

                    var leftBnd = new Binding();
                    leftBnd.Path = new PropertyPath("X");
                    leftBnd.Source = player;
                    leftBnd.Converter = this.PlayerXConverter;
                    ps.SetBinding(Canvas.LeftProperty, leftBnd);

                    var topBnd = new Binding();
                    topBnd.Path = new PropertyPath("Y");
                    topBnd.Source = player;
                    topBnd.Converter = this.PlayerYConverter;
                    ps.SetBinding(Canvas.TopProperty, topBnd);

                    MainCanvas.Children.Add(ps);
                }
	    }
	    #endregion


	}

    public class RadToDegConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return (double) value - 90; //+Math.PI;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    public class PlayerCoordConverter : IValueConverter
    {
        public enum CoordType
        {
            X,
            Y
        }

        public CoordType Type;

        public MapControl Control;

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value is double)
            {
                if (Type == CoordType.X)
                    return Control.AlfaX*(double) value + Control.BetaX;
                else
                    return Control.AlfaY*(double) value + Control.BetaY;
            }
            
            return null;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    public class PlayerColorConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value is int || value is double)
            {
                var team = System.Convert.ToInt32(value);

                if (team == 2)
                    return new SolidColorBrush(Colors.Red);

                if (team == 3)
                    return new SolidColorBrush(Colors.Blue);

                return new SolidColorBrush(Colors.Transparent);
            }

            return new SolidColorBrush(Colors.Transparent);
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }


    public class PlayerScaleConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var src = (PlayerData) value;

            if (src.IsMainPlayer)
                return 2;

            if (src.IsHighlightedPlayer)
                return 1.5;

            return 1.0;

        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    public class OprativeNumberConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var coef = double.Parse(parameter.ToString());

            return ((double) value)*coef;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}